<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1,maximum-scale=1"/>
    <title>Custom Force Manipulation</title>
    <link rel="stylesheet" type="text/css" href="../../css/styles.css"/>
    <script type="text/javascript" src="../../lib/d3.js"></script>

    <style type="text/css">
        .touch{
            fill-opacity: .2
        }
    </style>
</head>

<body>

<script type="text/javascript">
    var svg = d3.select("body").append("svg"),
            colors = d3.scaleOrdinal(d3.schemeCategory20c),
            r = 4.5,
            w = 1290,
            h = 800;

    svg.attr("width", w).attr("height", h);

    var force = d3.forceSimulation()
                    .velocityDecay(0.8)
                    .alphaDecay(0)
                    .force("charge", d3.forceManyBody().strength(-30))
                    .force("x", d3.forceX(w / 2))
                    .force("y", d3.forceY(h / 2))
                    .force("collision", d3.forceCollide(r + 0.5).strength(1));

    var nodes = [], centers = [];

    for (var i = 0; i < 5; ++i) {
        for (var j = 0; j < 50; ++j) {
            nodes.push({
                x: w / 2 + offset(),
                y: h / 2 + offset(),
                color: colors(i), // <-A
                type: i // <-B
            });
        }
    }

    force.nodes(nodes);

    function offset() {
        return Math.random() * 100;
    }

    function boundX(x) {
        return x > (w - r) ? (w - r): (x > r ? x : r);
    }

    function boundY(y){
        return y > (h - r) ? (h - r) : (y > r ? y : r);
    }

    svg.selectAll("circle")
                .data(nodes).enter()
            .append("circle")
            .attr("class", "node")
            .attr("cx", function (d) {return d.x;})
            .attr("cy", function (d) {return d.y;})
            .attr("fill", function(d){return d.color;})
            .attr("r", 1e-6)
                .transition()
            .attr("r", r);

    force.on("tick", function() {
        var k = 0.1;
        nodes.forEach(function(node) {
            var center = centers[node.type];
            if(center){
                node.x += (center[0] - node.x) * k; // <-C
                node.y += (center[1] - node.y) * k; // <-D
            }
        });

        svg.selectAll("circle")
            .attr("cx", function (d) {return boundX(d.x);})
            .attr("cy", function (d) {return boundY(d.y);});
    });

    d3.select("body")
        .on("touchstart", touch)
        .on("touchend", touch);

    function touch() {
        d3.event.preventDefault();

        centers = d3.touches(svg.node());

        var g = svg.selectAll("g.touch")
                .data(centers, function (d) {
                    return d.identifier;
                });

        g.enter()
            .append("g")
            .attr("class", "touch")
            .attr("transform", function (d) {
                return "translate(" + d[0] + "," + d[1] + ")";
            })
            .append("circle")
                .attr("class", "touch")
                .attr("fill", function(d){return colors(d.identifier);})
                    .transition()
                .attr("r", 50);

        g.exit().remove();
    }
</script>

</body>

</html>